#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/types.h>
#include<linux/slab.h>

/**
 * 练习内核的list_head的使用
 * LIST_HEAD 定义一个链表头
 * INIT_LIST_HEAD 初始化链表节点
 * list_add_tail 把一个节点添加到链表的尾部
 * list_for_each_entry_safe 遍历链表
 */
struct tdata {
    int data;
    struct list_head list;
};

LIST_HEAD(birth_list);

static struct tdata *make_tdata(int data)
{
    struct tdata *pdata;
    pdata = kmalloc(sizeof(struct tdata), GFP_KERNEL);

    if (pdata == NULL)
        return NULL;


    pdata->data = data;

    INIT_LIST_HEAD(&pdata->list);
    return pdata;
}

static int __init mymod_init(void)
{
    printk("mymod helloworld\n");

    struct tdata *pdata;
    int i;
    for (i = 0; i < 6; i ++) {
        pdata = make_tdata(i);
        if (pdata == NULL)
            return -1;

        list_add_tail(&pdata->list, &birth_list);
    }
    return 0;
}

static void __exit mymod_exit(void)
{
    struct tdata *ptr, *next;
    int i = 0;
    list_for_each_entry_safe(ptr, next, &birth_list, list) {
        printk("tdata[%d] = %d, ", i, ptr->data);

        list_del(&ptr->list);
        kfree(ptr);
        i ++;
    }
    printk("mymod_exit!\n");
}

module_init(mymod_init);
module_exit(mymod_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TEST");
MODULE_AUTHOR("gcj");